package com.qf.bigdata.service.impl;

import com.qf.bigdata.bean.DauPredictInfo;
import com.qf.bigdata.bean.RetentionCurveInfo;
import com.qf.bigdata.repository.PrestoQuery;
import com.qf.bigdata.service.PredictDAUService;
import com.qf.bigdata.util.Leastsq;
import com.qf.bigdata.util.Sample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.ujmp.core.Matrix;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Service
public class PredictDAUServiceImpl implements PredictDAUService {

    @Autowired
    private PrestoQuery prestoQuery;

    @Override
    public DauPredictInfo predict(String startDate, String endDate, int gap, int scale, int dnu) {
        DauPredictInfo dpi=new DauPredictInfo();
        try {
            List<Sample> samples=prestoQuery.queryRetention(startDate,endDate,gap);
            //线性变换
            for (Sample sample:samples) {
                sample.setX(Math.log(sample.getX()));
                sample.setY(Math.log(sample.getY()));
            }

            Matrix theta= Leastsq.matrixSolve(samples);
            double theta0=theta.getAsDouble(0,0);
            double theta1=theta.getAsDouble(1,0);
            //a,b   =>  theta0=lna,b=theta1
            double a=Math.pow(Math.E,theta0);
            double b=theta1;
            BigDecimal bda=new BigDecimal(a).setScale(3, RoundingMode.HALF_UP);
            BigDecimal bdb=new BigDecimal(b).setScale(3, RoundingMode.HALF_UP);


            RetentionCurveInfo rci=new RetentionCurveInfo();
            rci.setTheta0(bda.doubleValue());
            rci.setTheta1(bdb.doubleValue());
            rci.setEquation(String.format("y=%s * x^%s",bda.doubleValue(),bdb.doubleValue()));
            rci.setSamples(samples);

            //rrMap
            LinkedHashMap<String, Double> rrMap=new LinkedHashMap<>();
            Calendar calendar=Calendar.getInstance();
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
            calendar.setTime(sdf.parse(startDate));

            for (int i = 1; i <= scale; i++) {
                calendar.add(Calendar.DAY_OF_YEAR,1);
                String date=sdf.format(calendar.getTime());
                rrMap.put(date,bda.doubleValue()*Math.pow(i,bdb.doubleValue()));//ax^b
            }

            rci.setRrMap(rrMap);

            dpi.setRci(rci);
            dpi.setCode(200);
            dpi.setMsg("ok");

            LinkedHashMap<String, Integer> predictDAU=new LinkedHashMap<>();
            //put
            double tmpRr=0;
            for (Map.Entry<String,Double> kv:rrMap.entrySet()) {
                int dau=0;
                //dau=dnu*(1+r1+r2+...rn)
                tmpRr+=kv.getValue();
                dau=(int)(dnu*(1+tmpRr));
                predictDAU.put(kv.getKey(),dau);
            }
            dpi.setPredictDAU(predictDAU);

        } catch (Exception e) {
            dpi.setCode(-1);
            dpi.setMsg("some error");
            e.printStackTrace();
        }
        return dpi;
    }
}
